package com.acme.bankapp.domain.account;

import com.acme.bankapp.exception.IllegalAccountCreationException;
import com.acme.bankapp.exception.NotEnoughFundsException;
import com.acme.bankapp.exception.OverDraftLimitExceededException;

public class CheckingAccount extends AbstractAccount {
    private double overdraft;

    public CheckingAccount(double initialBalance, double initialOverdraft) throws IllegalAccountCreationException {
        super(initialBalance);
        if (initialOverdraft < 0) {
            throw new IllegalAccountCreationException();
        }
        this.overdraft = initialOverdraft;
    }

    public double getOverdraft() {
        return overdraft;
    }

    public void decreaseOverdraft(double amount) {
        overdraft -= Math.abs(amount);
    }

    @Override
    public double maximumAmountToWithdraw() {
        return super.maximumAmountToWithdraw() + getOverdraft();
    }

    @Override
    public void withdraw(double x) throws OverDraftLimitExceededException {
        try {
            super.withdraw(Math.abs(x));
        } catch (NotEnoughFundsException e) {
            throw new OverDraftLimitExceededException(x);
        }
        if (getBalance() < 0) {
            compensateBalance();
        }
    }

    private void compensateBalance() {
        double delta = getBalance();
        decreaseOverdraft(delta);
        deposit(delta);
    }

    @Override
    public String toJSONString() {
        return super.toJSONString().replaceAll("overdraft=.*;", "overdraft=" + getOverdraft() + ";");
    }

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder(super.toString());
        sb.setCharAt(sb.length() - 1, ',');
        sb.append(" overdraft=").append(overdraft).append("]");
        return sb.toString();
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        if (!super.equals(o)) return false;

        CheckingAccount that = (CheckingAccount) o;
        return that.overdraft == overdraft;
    }

    @Override
    public int hashCode() {
        int result = super.hashCode();
        long temp;
        temp = Double.doubleToLongBits(overdraft);
        result = 31 * result + (int) (temp ^ (temp >>> 32));
        return result;
    }
}